<script setup lang="ts">
import type SelectProp from "./type/SelectProp.ts";
import type SelectEmit from "@/components/select/type/SelectEmit.ts";
import {computed, onMounted, ref} from "vue";
import {mixHexWithWhite} from "@/components/utils.ts";
import type SelectItem from "@/components/select/type/SelectItem.ts";

const $emit = defineEmits<SelectEmit>()

const $prop = withDefaults(defineProps<SelectProp>(), {
  placeholder: '请选择...',
  labelWidth: 80,
  required: false,
  borderColor: "#1c7bfb",
  searchable: false,
  multiple: false,
  options: () => []
})

//浮动框
const floatingRef = ref()
//选择框是否获得焦点
const focused = ref(false)
// 下拉框是否显示
const isShow = ref(false)
// 已选择的item
const selectedItems = ref<SelectItem[]>([])
// 计算已选择的数量
const selectedCount = computed(() => selectedItems.value.length)
// 搜索内容
const searchText = ref<string>()
// 边框颜色处理
const lightBorderColor = computed(() => mixHexWithWhite($prop.borderColor!, 0.85))
// 最终显示的下拉框内容
const finalOption = computed<SelectItem[]>(() => {
  // 需要搜索，则返回过滤后的内容
  if ($prop.searchable && searchText.value) {
    return $prop.options.filter(item =>
        item.label && searchText.value && item.label.includes(searchText.value)
    );
  }
  // 不需要搜索，则显示全部内容
  else {
    return $prop.options
  }
})

const itemChange = (item: SelectItem) => {
  // 单选
  if (!$prop.multiple) {
    selectedItems.value.length = 0
    selectedItems.value.push(item)
    isShow.value = false
  }
  // 多选
  else {
    const index = selectedItems.value.findIndex(i => i.value === item.value)
    // 如果该元素存在，则移除
    if (index > -1) {
      selectedItems.value.splice(index, 1);
    }
    // 否则添加
    else {
      selectedItems.value.push(item)
    }
  }

  updateModelValue(item.value)
}

const itemClose = (code: string | number) => {
  const index = selectedItems.value.findIndex(i => i.value === code)
  if (index > -1) {
    selectedItems.value.splice(index, 1);
  }

  updateModelValue(code)
}

const updateModelValue = (key: string | number | boolean) => {
  let newVal
  if (Array.isArray($prop.modelValue)) {
    newVal = [...selectedItems.value.map(i => i.value)]
  } else {
    newVal = key
  }

  // 修改modelValue双向数据
  $emit('update:modelValue', newVal)
}

const selectFocus = () => {
  focused.value = true
}

const selectBlur = () => {
  focused.value = false
  floatingRef.value?.toggle(false)
}

onMounted(() => {
  if (!$prop.modelValue) {
    return
  }
  let preItems: (string | number | boolean)[]
  if (Array.isArray($prop.modelValue)) {
    preItems = $prop.modelValue
  } else {
    preItems = [$prop.modelValue]
  }

  ($prop.options.filter(item => preItems.includes(item.value))).forEach(item => itemChange(item))
})

</script>

<template>
  <div class="select-container" ref="selectContainer">

    <!-- 标题 -->
    <template v-if="label">
      <div class="select-label">
        <span>{{ label }}</span>
        <span v-if="required" style="color: #d03050">&nbsp;*</span>
        <span v-else style="visibility: hidden">&nbsp;*</span>
      </div>

    </template>

    <!-- 下拉框 -->
    <div class="select-content">
      <t-floating v-model="isShow" :offset="1" trigger="click" ref="floatingRef">

        <!-- 下拉框触发器 -->
        <div tabindex="-1" class="select-body" :class="{focused}" @focus="selectFocus" @blur="selectBlur">

          <span v-if="!selectedItems || selectedItems.length === 0" style="color: #757575; font-size: 14px">
            {{ placeholder }}
          </span>

          <t-tag v-for="(item, index) in selectedItems"
                 v-show="selectedCount <= 2 || index < 2"
                 :style="!multiple && selectedItems.length === 1 ? { width: '70%' } : {}"
                 :type="item.type ?? 'primary'"
                 :code="item.value" :key="item.value" :label="item.label"
                 @close="(code: string | number) => itemClose(code)" closeable @click.stop/>

          <span class="more-text" v-if=" selectedCount > 2">
              ...等{{ selectedCount }}项
          </span>

          <component class="arrow-down" is="arrow-down" style="color: #c2c2c2"/>
        </div>

        <template #floating>
          <template v-if="searchable">
            <t-input v-model="searchText" placeholder="请输入" clearable>
              <template #prefix>
                <component is="search"/>
              </template>

              <template #suffix>
                <t-btn pageSize="small" ghost>搜索</t-btn>
              </template>
            </t-input>
          </template>

          <!-- 下拉框内容 -->
          <div v-for="item in finalOption"
               class="select-item" :class="{checked: selectedItems.find(i => i.value === item.value)}"
               :key="String(item.value)"
               @click="itemChange(item)">
            <span class="item-label">{{ item.label }}</span>
            <component is="check" v-if="selectedItems.find(i => i.value === item.value)"/>
          </div>
        </template>
      </t-floating>
    </div>

  </div>
</template>

<style scoped>
.select-container {
  display: flex;
  align-items: center;
  width: 100%;
  line-height: 1;
  font-size: 14px;
  margin: 4px;
  gap: 3px;
}

.select-label {
  width: v-bind(labelWidth+ 'px');
  text-align: right;
}

.select-content {
  height: 30px;
  width: calc(100% - v-bind(labelWidth+ "px") - 8px);
}

.select-body {
  height: 30px;
  border: 1px solid #e0e0e6;
  border-radius: 2px;
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: 0 4px;
  gap: 2px;
  overflow: hidden;
  position: relative;

  background-color: white;
  box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.08), inset -1px -1px 1px rgba(255, 255, 255, 0.6);
}

.more-text {
  color: #666;
  font-size: 12px;
  white-space: nowrap;
  margin-left: 4px;
}

.select-body:hover {
  border-color: v-bind(borderColor);
}

.select-body.focused {
  border-color: v-bind(borderColor);
  box-shadow: 0 0 0 2px v-bind(lightBorderColor);
}

.arrow-down {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
}

.select-item {
  margin: 4px 0;
  padding: 4px 10px;
  min-height: 30px;
  cursor: pointer;
  transition: background-color 300ms ease;
  user-select: none;

  display: flex;
  align-items: center;
  justify-content: space-between;
}

.select-item:hover {
  background-color: #f3f3f5;
}

.select-item.checked {
  color: v-bind(borderColor);
}

.item-label {
  flex: 1;
}
</style>